<?php
/**
 * Project:     Formulário html
 * File:        form.php
 * @author 		Adriano Carneiro de Moura - adrianodemoura - gmail.com
 * @package mouraform
 */
/**
 * @package mouraform
 */
class MouraForm {
	/**
	 * Cabeçalho meta
	 */
	public $meta = "";
	
	/**
	 * Matriz com todos os dados do formulário
	 */
	public $form = array();
	
	/**
	 * Erros do formulário
	 */
	public $erros = array();
	
	/**
	 * Matriz com todos os campos de um formulário e suas propriedades que ficam guardadas na tag lang do elemento form
	 */
	public $campos = array();
	
	/**
	 * indexação dos campos
	 */
	private $tabindex = 0;
	
	/**
	 * Configura as propriedades do formulário, com valores de padrão, caso ainda não tenham sido informadas
	 * @param array $f informações do formulário
	 * @param array $c campos do formulário
	 * @param string $d diretório
	 * @return void
	 */
	public function setForm($f=array(), $c=array(), $d="")
	{
		
		// configurando o formulário com o parâmetro de formulário
		$this->form 	= $f;
		
		// atualizando formulário
		if (!$this->form["nome"]) 		$this->form["nome"] 	= "form";
		if (!$this->form["metodo"]) 	$this->form["metodo"] 	= "post";
		if (!$this->form["enter"]) 		$this->form["enter"] 	= 1;
		if (!$this->tabindex) 			$this->tabindex = 1;
		if (!$this->form["action"])
		{
			$caminho = pathinfo($_SERVER["PHP_SELF"]);
			$this->form["action"] = $caminho["basename"];
		}

		// configurando o cabeçalho meta
		$this->meta = "<link type='text/css' href='".$d."mouraform.css'	rel='stylesheet' media='all' />\n";
		if ($this->form["ajax"])
		{
			$this->meta .= "\t<script type='text/javascript' src='".$d."md5.js'></script>\n";
			$this->meta .= "\t<script type='text/javascript' src='".$d."ajax.js'></script>\n";
		}
		$this->meta .= "\t<script type='text/javascript' src='".$d."validacao.js'></script>\n";
		$this->meta .= "\t<script type='text/javascript' src='".$d."mouraform.js'></script>\n";
		
		// configurando os campos do formulário com o parâmetro de campos
		$this->campos 	= $c;
		
		// evento submit do formulário
		if ($this->form["ajax"])
		{
			$this->form["submit"] = "if (getValidacaoLocal(\"".$this->form["nome"]."\")) return getValidacaoServidor(\"".$this->form["nome"]."\",\"".$this->form["jsDepois"]."\"); else return false;";
		} else
		{
			$this->form["submit"] = "return getValidacaoLocal(\"".$this->form["nome"]."\")";
		}

		// atualizando os botões do formulário
		if (!isset($this->form["botoes"])) $this->form["botoes"] = array();
		if (count($this->form["botoes"]))
		{
			foreach($this->form["botoes"] as $botao => $propriedades)
			{
				if (!isset($this->form["botoes"][$botao]["tipo"])) $this->form["botoes"][$botao]["tipo"] = "button";
			}
		} else
		{
			$this->form["botoes"]["enviar"]["valor"] 	= "Enviar";
			$this->form["botoes"]["enviar"]["tipo"] 	= "submit";
			$this->form["botoes"]["limpar"]["valor"] 	= "Limpar";
			$this->form["botoes"]["limpar"]["tipo"] 	= "reset";
			$this->form["botoes"]["fechar"]["valor"] 	= "Fechar";
			$this->form["botoes"]["fechar"]["tipo"] 	= "button";
			$this->form["botoes"]["fechar"]["link"] 	= ".";
		}
		
		// atualizando os campos
		if (count($this->campos))
		{
			foreach($this->campos as $campo => $propriedades)
			{
				// tipo padrão igual text
				if (!isset($propriedades["tipo"]))
				{
					$this->campos[$campo]["tipo"] = "text";
				} else
				{
					if ($this->campos[$campo]["tipo"]=="") $this->campos[$campo]["tipo"] = "text";
				}
				
				// verificando o título
				if (!$propriedades["titulo"]) $this->campos[$campo]["titulo"] = $campo;
				
				// verificando caixa
				switch($propriedades["caixa"])
				{
					case "ma":
						$this->campos[$campo]["valor"] = mb_strtoupper($this->campos[$campo]["valor"],"utf-8");
						break;
					case "mi":
						$this->campos[$campo]["valor"] = mb_strtolower($this->campos[$campo]["valor"],"utf-8");
						break;
				}
				
				// verificando tipo
				$tipo = $propriedades["tipo"];
				switch($tipo)
				{
					case "cpf":
						$this->campos[$campo]["tamanhomaximo"] 	= 14;
						$this->campos[$campo]["mascara"] 		= "###.###.###-##";
						break;
					case "cnpj":
						$this->campos[$campo]["tamanhomaximo"] 	= 18;
						$this->campos[$campo]["mascara"] 		= "##.###.###/####-##";
						break;
					case "data":
					case "date":
						$this->campos[$campo]["tamanhomaximo"] 	= 10;
						$this->campos[$campo]["mascara"] 		= "##/##/####";
						break;
					case "cep":
						$this->campos[$campo]["mascara"] 		= "##.###-###";
						$this->campos[$campo]["tamanhomaximo"] 	= 10;
						$this->campos[$campo]["tamanhominimo"] 	= 10;
					case "telefone":
						$this->campos[$campo]["tamanhomaximo"] 	= 12;
						$this->campos[$campo]["tamanhominimo"] 	= 8;
						break;
				}
				
				// verificando o tamanho do campo
				if ((!isset($propriedades["estilo"]) || strpos("width",$propriedades["estilo"])) && $propriedades["tipo"] != "hidden" )
				{
					$tam = ($this->campos[$campo]["tamanhomaximo"]*8);
					if ($tam < 30 )  $tam = 30;
					if ($tam > 400 ) $tam = 400;
					$this->campos[$campo]["estilo"] = "width: ".$tam."px;";
				}

			}
		}
	}
	
	/**
	 * Retorna o formulário
	 * @param string $form Nome do formulário
	 * @param array $campos Matriz contendo somentes os campos que serão usados neste formulário, se estiver vazia todos os campos serão usados.
	 * @return string $retorno
	 */
	public function getForm($camposForm=array())
	{
		// verificando se é uma array válida
		if ($camposForm && !is_array($camposForm)) return "O parâmetro para o método getForm deve ser uma array";
		
		// definindo os campos deste formulário		
		if (!count($camposForm) && count($this->campos))
		{
			foreach($this->campos as $campo => $propriedades) // dando um loop em cada campo
			{
				array_push($camposForm,$campo);
			}
		}
		
		// div para o formulário
		$retorno .= "\n<div id='".$this->form["nome"]."_form' class='formulario'";
		if ($this->form["estilo"]) $retorno .= " style='".$this->form["estilo"]."'";
		$retorno .=">\n\n";
		
		// se o form vai postar via ajax, cria a div que vai receber a animação reload
		$retorno .= "<div id='reload_ajax'></div>\n";
		
		// mensagem de título
		if ($this->form["titulo"])
		{
			$retorno .= "<p class='form_titulo'>".$this->form["titulo"]."</p>\n\n";
		}
		
		// mensagem do cabeçalho
		if ($this->form["subtitulo"])
		{
			$retorno .= "<p class='form_subtitulo'>".$this->form["subtitulo"]."</p>\n\n";
		}
		
		// início do formulário
		$retorno .= "<form id='".$this->form["nome"]."' method='".$this->form["metodo"]."'";
		
		// campos opcionais
		if ($this->form["classe"]) $retorno .= " class='".$this->form["classe"]."'";
		if ($this->form["action"]) $retorno .= " action='".$this->form["action"]."'";
		if ($this->form["submit"]) $retorno .= " onsubmit='".$this->form["submit"]."'";
		
		// fim start form
		$retorno .= ">\n";
		
		// incrementando campo a campo conforme seu tipo
		if (count($camposForm))
		{
			foreach($camposForm as $campo)
			{
				if ($campo != "#")
				{
					switch($this->campos[$campo]["tipo"])
					{
						case "select":
							$retorno .= "\n".$this->getSelect($campo);
							break;
						case "textarea":
							$retorno .= "\n".$this->getTextarea($campo);
							break;
						case "radio":
							$retorno .= "\n".$this->getRadio($campo);
							break;
						case "checkbox":
							$retorno .= "\n".$this->getCheck($campo);
							break;
						default:
							$retorno .= "\n".$this->getText($campo);
					}
					if (!isset($this->campos[$campo]["tabindex"])) $this->tabindex++;
				} else
				{
					$retorno .= "\t<p class='quebra_linha'><br /></p>\n";
				}
			}
		}
		
		// incrementando os botões
		$retorno .= "\n\t<div id='form_botoes'>\n";
		foreach($this->form["botoes"] as $botao => $propriedades)
		{
			$retorno .= "\t".$this->getButton($botao)."\n";
		}
		$retorno .= "\t</div>\n\n";
		
		// erros
		$retorno .= "\t<div id='form_alerta'>\n";
		if ($this->form["msg_alerta"])
		{
			$retorno .= "\t\t".$this->form["msg_alerta"]."\n";
			$retorno .= "\t\t<script type='text/javascript'>\n";
			$retorno .= "\t\t\tsetTimeout(\"document.getElementById('form_alerta').style.display='none'\",6000);\n";
			$retorno .= "\t\t</script>\n";
		}
		$retorno .= "\t</div>\n\n";

		// fim do formulário
		$retorno .= "</form>\n\n";
		
		// mensagem de rodapé
		$retorno .= "\t<div id='form_rodape'>\n";
		if ($this->form["msg_rodape"]) $retorno .= "\t\t".$this->form["msg_rodape"]."\n";
		$retorno .= "\t</div>";

		
		// fim da div form
		$retorno .= "</div>\n\n";

		// se o form vai postar via ajax, cria a div de resposta
		$retorno .= "<div id='resposta_ajax'></div>\n\n";

		// campo de primeiro focu
		if ($this->form["primeiro_foco"])
		{
			$retorno .= "<script type='text/javascript'>document.getElementById('".$this->getTitulo($this->form["primeiro_foco"])."').select();</script>\n";
		}
		
		// retornano o formulário
		return $retorno;
	}
	
	/**
	 * Retorna a validação do formulário, em caso de erro retorna o erro
	 * @return string $retorno
	 */
	public function getValidacao()
	{
		
		// validando campo a campo
		if (count($this->campos))
		{
			foreach($this->campos as $campo => $propriedades)
			{
				$_campo = $this->getTitulo($campo);
				
				// checando valor menor
				if ($propriedades["valor_menor"] && $propriedades["valor_menor"]>$_POST[$_campo])
				{
					array_push($this->erros,"Valor inválido para o campo $campo, tente algor maior que ".$propriedades["valor_menor"]);
				}

				// checando valor maior
				if ($propriedades["valor_maior"] && $propriedades["valor_maior"]>$_POST[$_campo])
				{
					array_push($this->erros,"Valor inválido para o campo $campo, tente algor menor que ".$propriedades["valor_maior"]);
				}

				// checando obrigatoriedade
				if ($propriedades["obrigatorio"] && !$_POST[$_campo])
				{
					array_push($this->erros,"O campo $campo, é de preechimento obrigatório ...");
				}

				// checando tamanho mínimo
				if ($propriedades["tamanhominimo"] && strlen($_POST[$_campo])<$propriedades["tamanhominimo"] && $propriedades["obrigatorio"])
				{
					array_push($this->erros,"O campo ".$propriedades["titulo"].", tem que ter no mínimo ".$propriedades["tamanhominimo"]." caracteres ".$_POST[$_campo]);
				}

				// checando tamanho máximo
				if ($propriedades["tamanhomaximo"] && ($propriedades["tipo"]!="senha" && $propriedades["tipo"]!="password") )
				{
					if (strlen($_POST[$_campo])>$propriedades["tamanhomaximo"])
					{
						array_push($this->erros,"O campo ".$propriedades["titulo"].", tem que ter no máximo ".$propriedades["tamanhomaximo"]." caracteres");
					}
				}
			}
		}
		
		// se ocorreu algum erro
		if (count($this->erros))
		{
			$retorno = false;
		} else
		{
			$retorno = true;
		}
	
		// retorno
		return $retorno;
	}
	
	/**
	 * Retorna a resposta do formulário em xml
	 * @msg 	string 		$msg 		mensagem
	 * @erro 	integer 	$erro 		1 para mensagem de erro 0 para mensagem ok
	 * @depois 	string 		$depois		Nome da função JavaScript a se executa depois que o servidor enviar a mensagem
	 * @oculta	integer		$oculta		Tempo de timeOut para oculta a resposta a mensagem
	 * @return 	string 		$retorno 	Texto em formato xml
	 */
	public function getXml($msg="",$alerta=0, $depois="0", $oculta=3000)
	{
		Header("Content-type: application/xml; charset=utf-8");
		$retorno = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
		$retorno .= "<xml>\n";
		$retorno .= "<resposta_ajax>$msg</resposta_ajax>\n";
		$retorno .= "<resposta_ajax_alerta>$alerta</resposta_ajax_alerta>\n";
		$retorno .= "<resposta_ajax_depois>$depois</resposta_ajax_depois>\n";
		$retorno .= "<resposta_ajax_oculta>$oculta</resposta_ajax_oculta>\n";
		$retorno .= "</xml>\n";
		return $retorno;
	}

	
	/**
	 * Retorna o seu tipo em linguagem html
	 * @return string $retorno
	 */
	private function getTipo($tipo="")
	{
		switch($tipo)
		{
			case "select":
				$retorno = "select";
				break;
			case "senha":
				$retorno = "password";
				break;
			case "cpf":
			case "cnpj":
			case "cep":
			case "email":
			case "telefone":
			case "data":
			case "date":
			case "numero":
			case "timestamp":
				$retorno = "text";
				break;
		}
		if (!$retorno) $retorno = $tipo;
		return $retorno;
	}
		
	/**
	 * Retorna a tag html input, com seus eventos e propriedades
	 * @return string $retorno
	 */
	private function getText($campo="")
	{
		// retorno padrão
		$retorno 		= "";
		
		// título do campo
		$_campo = $this->getTitulo($campo);
		
		// iniciando a linha do formulário
		$retorno .= "\t<div id='id_".$_campo."' class='linha'>\n";
		
		// título do campo
		if ($this->campos[$campo]["titulo"] && $this->campos[$campo]["tipo"] != "hidden")
		{
			$retorno .= "\t<label class='la_".$_campo."'";
			if ($this->campos[$campo]["estilot"]) $retorno .= " style='".$this->campos[$campo]["estilot"]."'";
			$retorno .= ">";
			if ($this->campos[$campo]["obrigatorio"]) $retorno .= " * ";
			$retorno .= $this->campos[$campo]["titulo"];
			$retorno .= "</label>\n";
		}
		
		// valor do campo
		$valor = $this->getValor($this->campos[$campo]["valor"],$this->campos[$campo]["tipo"]);
		
		// campos obrigatórios do elemento text
		$retorno .= "\t<input type='".$this->getTipo($this->campos[$campo]["tipo"])."' name='".$_campo."' id='".$_campo."' class='in_input' value='".$valor."'";
		
		// definindo a ordem de tabulação
		if (!isset($this->campos[$campo]["tabindex"]))
		{
			$retorno .= " tabindex='".$this->tabindex."'";
		} else
		{
			$retorno .= " tabindex='".$this->campos[$campo]["tabindex"]."'";
		}
		
		// desabilitando o campo
		if ($this->campos[$campo]["desativar"]==1)
		{
			//$retorno .= " disabled='disabled'";
			$retorno .= " readonly='readonly'";
		}
		
		// campos opcionais
		if ($this->campos[$campo]["tamanhomaximo"]) $retorno .= " maxlength='".$this->campos[$campo]["tamanhomaximo"]."'";
		if ($this->campos[$campo]["legenda"]) 		$retorno .= "\n\t\ttitle='".$this->campos[$campo]["legenda"]."'";
		if ($this->campos[$campo]["estilo"]) 		$retorno .= "\n\t\tstyle='".$this->campos[$campo]["estilo"]."'";
		if ($this->campos[$campo]["classe"]) 		$retorno .= "\n\t\tclass='".$this->campos[$campo]["classe"]."'";

		//		
		if ($this->campos[$campo]["tipo"] != "hidden")
		{
			$retorno .= "\n\t\tlang='".$this->getPropriedades($campo)."' ";
			$retorno .= "\n\t\t".$this->getEventos($campo);
		}
		
		// fim do elemento text
		$retorno .= "\t/>\n";
		
		// dica
		if ($this->campos[$campo]["dica"])
		{
			$retorno .= "\t";
			$retorno .= "<span class='sp_dica'>";
			$retorno .= $this->campos[$campo]["dica"];
			$retorno .= "</span>\n";
		}
		
		// fim da linha
		$retorno .= "\t</div>\n";
		
		// retorno
		return $retorno;
	}
	
	/**
	 * Retorna o elemento button do formulário
	 * @return string $retorno
	 */
	private function getButton($botao="")
	{
		// retorno padrão
		$retorno = "";
		
		// campos obrigatórios do elemento button
		$retorno .= "\t<input type='".$this->form["botoes"][$botao]["tipo"]."' name='$botao' id='$botao' class='bt_$botao' value='".$this->form["botoes"][$botao]["valor"]."'";
		
		// definindo a ordem de tabulação
		if (!isset($this->form["botoes"][$botao]["tabindex"]))
		{
			$retorno .= " tabindex='".$this->tabindex."'";
			$this->tabindex++;
		} else
		{
			$retorno .= " tabindex='".$this->form["botoes"][$botao]["tabindex"]."'";
		}

		// eventon onClick causando redirecionamento
		if ($this->form["botoes"][$botao]["link"])
		{
			$retorno .= " onclick='document.location.href=\"".$this->form["botoes"][$botao]["link"]."\"'";
		}
		
		// evento onclik executando escript
		if ($this->form["botoes"][$botao]["onclick"])
		{
			$retorno .= " onclick='javascript:".$this->form["botoes"][$botao]["onclick"]."'";
		}
		
		// fim botão
		$retorno .= "/>\n";
		
		return $retorno;
	}
	
	/**
	 * Retorna os eventos de um campo de formulário com base em suas propriedades
	 * @return string $retorno
	 */
	private function getEventos($campo)
	{
		$retorno 		= "";
		$on_key_down	= "";
		$on_key_up		= "setErroLocal(this); ";
		//$on_key_press 	= "setTecla(this,event); "; // está ocorrendo erro intermitente ao pressionar enter
		$on_key_press 	= "";
		$on_change		= "";
		$on_blur		= "setErroLocal(this); ";
		
		// se possui máscara
		if ($this->campos[$campo]["mascara"])
		{
			$on_key_press 	.= "getMascara(this,'".$this->campos[$campo]["mascara"]."')";
		}
		
		// concatenando onblur
		if ($on_blur)
		{
			$retorno .= "onblur=\"".$on_blur."\"\n";
		}

		// concatenando onkeyup
		if ($on_key_up)
		{
			$retorno .= "\t\tonkeyup=\"".$on_key_up."\"\n";
		}
		
		// concatenando onkeydown
		if ($on_key_down)
		{
			$retorno .= "\t\tonkeydown=\"".$on_key_down."\"\n";
		}
		
		// concatenando onkeypress
		if ($on_key_press)
		{
			$retorno .= "\t\tonkeypress=\"".$on_key_press."\"\n";
		}
		
		// concatenando onchange
		if ($on_change)
		{
			$retorno .= "\t\tonchange=\"".$on_change."\"\n";
		}
		
		return $retorno;
	}
	
	/**
	 * Retorna as propriedades do campo de formulário que serão usadas no javascript para validação
	 * @return string $retorno
	 */
	private function getPropriedades($campo)
	{
		$retorno = "-";
		
		foreach($this->campos[$campo] as $propriedade => $valor)
		{
			switch($propriedade)
			{
				case "titulo":
					$retorno .= str_replace(" ","_","titulo$valor-");
					break;
				case "obrigatorio":
					$retorno .= "obrigatorio1-";
					break;
				case "duplicidade":
					$retorno .= "duplicidade1-";
					break;
				case "tamanhominimo":
					$retorno .= "tamanhominimo$valor-";
					break;
				case "tipo":
					$retorno .= "tipo$valor-";
					break;
				case "caixa":
					$retorno .= "caixa$valor-";
				case "clone":
					$retorno .= "clone".$this->getTitulo($valor)."-";
					break;
			}
		}
		
		// retorno
		return $retorno;
	}
	
	/**
	 * Retorna o elemento select
	 * @return string $retorno
	 */
	private function getSelect($campo="")
	{
		$retorno = "\r";
		$retorno .= "<select id='$campo' name='$campo'>\n";
		foreach ($this->campos[$campo]->valores as $chave => $valor)
		{
			if ($chave==$selecionado) $selecao = " selected='selected' "; else $selecao="";
			$retorno .= "\t<option value='$chave'$selecao>$valor</option>\n";
		}
		$retorno .= "</select>\n";
		return $retorno;
	}
	
	/**
	 * Retorna o elemento radio
	 * @return string $retorno
	 */
	 private function getRadio($campo="") 
	 {
	 	$retorno = "\r";
	    foreach($this->campos[$campo]["valores"] as $key=> $valor)
		{
	        if($key == $selecionado)
			{
				$retorno .="<label><input type='radio' name='$campo' id='$campo' value='$key' checked />$valor</label>$separador";
			} else
			{
				$retorno .="<label><input type='radio' name='$campo' id='$campo' value='$key' />$valor</label>$separador";
        	}
		}
		return $retorno;
	}
	
	/**
	 * Remove acentuação
	 * @param string $var
	 * @return string $var
	 */
	private function getSemAcentuacao($var="")
	{
		$var = str_replace("ç","c",$var);
		$var = str_replace("Ç","C",$var);
		
		$var = str_replace("á","a",$var);
		$var = str_replace("à","a",$var);
		$var = str_replace("â","a",$var);
		$var = str_replace("ã","a",$var);
		$var = str_replace("Á","A",$var);
		$var = str_replace("À","A",$var);
		$var = str_replace("Â","A",$var);
		$var = str_replace("Ã","A",$var);
		
		$var = str_replace("é","e",$var);
		$var = str_replace("è","e",$var);
		$var = str_replace("ê","e",$var);
		$var = str_replace("É","E",$var);
		$var = str_replace("È","E",$var);
		$var = str_replace("Ê","E",$var);

		$var = str_replace("í","i",$var);
		$var = str_replace("ì","i",$var);
		$var = str_replace("î","i",$var);
		$var = str_replace("Í","I",$var);
		$var = str_replace("Ì","I",$var);
		$var = str_replace("Î","I",$var);
		
		$var = str_replace("ó","o",$var);
		$var = str_replace("ò","o",$var);
		$var = str_replace("ô","o",$var);
		$var = str_replace("õ","o",$var);
		$var = str_replace("Ó","O",$var);
		$var = str_replace("Ò","O",$var);
		$var = str_replace("Ô","O",$var);
		$var = str_replace("Ô","O",$var);
		
		$var = str_replace("ú","u",$var);
		$var = str_replace("ù","u",$var);
		$var = str_replace("û","u",$var);
		$var = str_replace("ũ","u",$var);
		$var = str_replace("Ú","U",$var);
		$var = str_replace("Ù","U",$var);
		$var = str_replace("Û","U",$var);
		$var = str_replace("Û","U",$var);

		return $var;
	}
	
	/**
	 * Retorna o valor do campo formatado para seu tipo
	 * @param string $val
	 * @param string $tip
	 * @return string $retorno
	 */
	private function getValor($val="", $tip="")
	{
		switch($tip)
		{
			case "timestamp":
				$retorno = date("d/m/Y H:i:s",strtotime($val));
				break;
			default:
				$retorno = $val;
		}
		
		return $retorno;
	}
	
	/**
	 * Retorna o título do campo
	 * @param string $campo Nome do campo
	 * @return string $retorno Título do campo formatado
	 */
	public function getTitulo($campo)
	{
		$titulo = $this->campos[$campo]["titulo"]>"" ? $this->campos[$campo]["titulo"] : $campo;
		$retorno = str_replace(" ","_",$this->getSemAcentuacao(mb_strtolower($titulo,"utf-8")));
		$retorno = str_replace("-","",$retorno);
		return $retorno;
	}

}

?>
